﻿using mozhi.smarterp.Finance.Enums;
using mozhi.smarterp.Finance.Treasuries.Payments;
using mozhi.smarterp.Finance.Treasuries.Payments.Repositories;
using mozhi.smarterp.Finance.Treasuries.Repositories;
using Mozhi.Abp.Domain.BasicData.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Domain.Services;
using Volo.Abp.Guids;

namespace mozhi.smarterp.Finance.Treasuries.Services
{
    public class PaymentRequisitionManager : DomainService
    {
        private IPaymentRepository _paymentRepository;
        private IGuidGenerator _guidGenerator;
        private IPaymentRequisitionRepository _repository;
        private ISupplierRepository _supplierRepository;
        private ICustomerRepository _customerRepository;
        private IEmployeeRepository _employeeRepository;
        private INumberGeneratorRepository _numberGeneratorRepository;
        private ICurrencyRepository _currencyRepository;
        private IPaymentRequisitionLinkRepository _paymentRequisitionLinkRepository;
        private PaymentManager _paymentManager;

     
        public PaymentRequisitionManager(IPaymentRepository paymentRepository, IGuidGenerator guidGenerator, IPaymentRequisitionRepository repository, 
            ISupplierRepository supplierRepository, ICustomerRepository customerRepository, IEmployeeRepository employeeRepository, INumberGeneratorRepository numberGeneratorRepository, 
            ICurrencyRepository currencyRepository, IPaymentRequisitionLinkRepository paymentRequisitionLinkRepository , PaymentManager paymentManager)
        {
            _paymentRepository = paymentRepository;
            _guidGenerator = guidGenerator;
            _repository = repository;
            _supplierRepository = supplierRepository;
            _customerRepository = customerRepository;
            _employeeRepository = employeeRepository;
            _numberGeneratorRepository = numberGeneratorRepository;
            _currencyRepository = currencyRepository;
            _paymentRequisitionLinkRepository = paymentRequisitionLinkRepository;
            _paymentManager = paymentManager;
        }

        public async Task<PaymentRequisition> GetAsync(Guid? id , PaymentRequisitionType type , DateTime date,TradingPartnerType tradingPartnerType, Guid? supplierId, Guid? employeeId, Guid? customerId,
            Guid currencyId, decimal exchangeRate, bool isAdvanced,string comment, DocumentStatusType status)
        {
            var supplier = supplierId.HasValue ? await _supplierRepository.GetAsync(supplierId.Value) : null;
            var customer = customerId.HasValue ? await _customerRepository.GetAsync(customerId.Value) : null;
            var employee = employeeId.HasValue ? await _employeeRepository.GetAsync(employeeId.Value) : null;
            var currency = await _currencyRepository.GetAsync(currencyId);

            PaymentRequisition requisition;
            if (id.HasValue)
            {
                requisition = await _repository.GetAsync(id.Value);

                if (requisition == null)
                    throw new UserFriendlyException($"付款申请单：{id}不存在", "100000");

                requisition.Change(date, exchangeRate, status, comment);
            }
            else
            {
                var number = await GetNextNumberAsync();

                requisition = new PaymentRequisition(_guidGenerator.Create(), number, date, type, tradingPartnerType, supplier, employee, customer, currency, exchangeRate, isAdvanced, status, comment);
            }

            return requisition;
        }

        public async Task<PaymentRequisitionItem> GetItemAsync(Guid? id, DocumentType? sourceDocumentType, Guid? sourceDocumentId, Guid? sourceDocumentEntryId, decimal? payableAmountFr, decimal? payableAmount, decimal requistionAmountFr,
            DateTime? dueDate, DateTime? expectedPaymentDate, string remark)
        {
            var item = new PaymentRequisitionItem(id ?? _guidGenerator.Create(), sourceDocumentType, sourceDocumentId, sourceDocumentEntryId, payableAmountFr, payableAmount, requistionAmountFr, null,
               dueDate, expectedPaymentDate, remark);

            return item;
        }

        public async Task DeleteAsync(Guid id)
        {
            var requisition = await _repository.GetAsync(id);

            if (requisition == null)
                throw new UserFriendlyException($"付款申请单：{id}不存在", "100000");

            if (requisition.Status != DocumentStatusType.Creation)
                throw new UserFriendlyException($"付款申请单：{requisition.Number}非创建状态，不允许删除", "100000");

            //校验是不是已经关联了付款单
            var paymentCount = await _paymentRequisitionLinkRepository.GetCountAsync(id, null);

            if (paymentCount > 0)
                throw new UserFriendlyException($"付款申请单：{requisition.Number}已关联付款单，不允许删除", "100000");

            await _repository.DeleteAsync(id);
        }

        public async Task<Guid> PushPaymentAsync(Guid id)
        {
            var requisition = await _repository.GetAsync(id);

            if (requisition == null)
                throw new UserFriendlyException($"付款申请单：{id}不存在", "100000");

            if(requisition.Status != DocumentStatusType.Approved)
                throw new UserFriendlyException($"付款申请单：{requisition.Number}非审核状态，不允许下推付款单", "100000");

            if(requisition.Items.IsNullOrEmpty())
                throw new UserFriendlyException($"付款申请单：{requisition.Number}没有明细数据，不能下推付款单", "100000");

            var links = await _paymentRequisitionLinkRepository.GetListAsync(id, null);

            Payment payment = null;

            List<Payment> genratedPayments = await _paymentRepository.GetListAsync(links.Select(x=>x.PaymentId).Distinct().ToList());

            if (genratedPayments.Count > 0)
            {
                var paymentTotalAmountFr = genratedPayments.Sum(x => x.AmountFr);

                if (paymentTotalAmountFr > requisition.AmountFr)
                    throw new UserFriendlyException($"付款申请单：{requisition.Number}已全部付款，不允许下推付款单", "100000");
            }

            //创建付款单
            payment = await _paymentManager.GetAsync(null, DateTime.UtcNow, null, requisition.SupplierId, requisition.EmployeeId, requisition.CustomerId, requisition.TradingPartnerType,
                requisition.CurrencyId, requisition.ExchangeRate, requisition.IsAdvanced, false, "", DocumentStatusType.Creation);

            var paymentItem = await _paymentManager.GetItemAsync(null, requisition.AmountFr - genratedPayments.Sum(x => x.AmountFr) , null , null);

            payment.SetItems(new List<PaymentItem> { paymentItem });

            //创建关联关系
            var paymentRequisitionLink = new PaymentRequisitionLink(_guidGenerator.Create(), payment.Id, requisition.Id);

            await _paymentRepository.InsertAsync(payment);

            await _paymentRequisitionLinkRepository.InsertAsync(paymentRequisitionLink);

            return payment.Id;
        }

        #region
        private async Task<string> GetNextNumberAsync()
        {
            var latestNumber = await _repository.GetLatestNumberAsync();

            var numberGenerator = await _numberGeneratorRepository.GetAsync((int)DocumentType.PaymentRequisition, latestNumber ?? "");

            if (numberGenerator == null)
                throw new UserFriendlyException($"未设置类型为：{DocumentType.PaymentRequisition}的编码规则", "100000");

            return numberGenerator?.Number;
        }
        #endregion
    }
}
